/* @flow */

import config from 'core/config'

import {
  warn,
  isObject,
  toObject,
  isReservedAttribute
} from 'core/util/index'

/**
 * Runtime helper for merging v-bind="object" into a VNode's data.
 * 在运行时将v-bind="object"的object对象合并到虚拟dom对象的data属性中
 * 示例：
 * <div v-bind.prop.sync="object"
 */
export function bindObjectProps (
  data: any, //createElement的data参数的值
  tag: string, //'div'标签名
  value: any, //object对应的值
  asProp: boolean, //如果v-bind存在.prop修饰符，则为true
  isSync?: boolean //如果v-bind存在.sync修饰符，则为true
): VNodeData {
  if (value) {
    if (!isObject(value)) {
      process.env.NODE_ENV !== 'production' && warn(
        'v-bind without argument expects an Object or Array value',
        this
      )
    } else {
      if (Array.isArray(value)) {
        //value是数组的情况下，toObject方法会循环数组中的所有对象，依次将对象
        //中的键和值设置到一个对象中，然后返回保存到value变量
        value = toObject(value)
      }
      let hash
      for (const key in value) {
        if (
          key === 'class' ||
          key === 'style' ||
          isReservedAttribute(key) //'key,ref,slot,is'
        ) {
          //直接将'class,style,key,ref,slot,is'直接设置到虚拟dom的data对象上
          //通过v-bind设置的这些属性比直接在标签上声明的同名属性的优先级低
          hash = data
        } else {
          const type = data.attrs && data.attrs.type
          hash = asProp || config.mustUseProp(tag, type, key)
            ? data.domProps || (data.domProps = {})
            : data.attrs || (data.attrs = {})
        }
        if (!(key in hash)) {
          hash[key] = value[key]

          //.sync的语法糖
          if (isSync) {
            const on = data.on || (data.on = {})
            on[`update:${key}`] = function ($event) {
              value[key] = $event
            }
          }
        }
      }
    }
  }
  return data
}
